#define _GNU_SOURCE
#include "app_device.h"
#include "log/log.h"
#include "app_common.h"
#include "app_message.h"
#include "app_mqtt.h"
#include "app_pool.h"
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> // file control

static Device *device;

/**
 * 初始化
 */
Device *app_device_init(char *filename)
{
    // 初始化设备内存
    device = malloc(sizeof(Device));

    // 初始化设备属性
    device->filename = filename;
    device->fd = open(filename, O_RDWR);
    device->up_buffer = app_buffer_init(1024);
    device->down_buffer = app_buffer_init(1024);
    device->is_running = 0; // 代表线程未启动运行
    device->last_write_time = 0;
    device->post_read = NULL;
    device->pre_write = NULL;

    log_debug("设备初始化成功");

    return device;
}

/**
 * 发送消息到远程的任务函数   由线程池中的某个分线程执行
 *
 */
static int send_task_func(void *arg)
{
    Device *device = (Device *)arg;
    // 从上行缓冲区读取到一个字符数组消息
    char chars_buf[128];
    int len = app_buffer_read(device->up_buffer, chars_buf, sizeof(chars_buf));
    if (len == -1)
    {
        log_error("从上行缓冲区读取数据失败");
        return -1;
    }
    // 将字符数组消息转换为json消息
    char *json = app_message_charsToJson(chars_buf, len);

    // 发送给远程
    app_mqtt_send(json);

    // 释放内存
    free(json);

    return 0;
}

/**
 * 不断读取下游设备传输过来的数据的线程
 */
static void *read_thread_func(void *arg)
{
    while (device->is_running)
    {
        // 从设备文件中读取数据
        char read_buf[128];
        ssize_t len = read(device->fd, read_buf, sizeof(read_buf));
        if (len == -1)
        {
            log_error("读取设备文件失败");
            return NULL;
        }
        // 对读取到蓝牙数据进行读后处理，转换为字符数组
        if (len > 0 && device->post_read)
        {
            len = device->post_read(read_buf, len);
            // 如果处理失败，返回
            if (len == -1)
            {
                log_error("设备数据读后处理失败");
                return NULL;
            }

            // 只有数据
            if (len > 0)
            {
                log_debug("读取到设备数据：%.*s", len, read_buf);
                // 将数据写入上行缓冲区
                app_buffer_write(device->up_buffer, read_buf, len);
                // 将发送消息的操作交给线程池执行
                app_pool_registerTask(send_task_func, device);
            }
        }
    }

    return NULL;
}

/**
 * 写入数据到设备文件的任务函数   由线程池中的某个分线程执行
 */
static int write_task_func(void *arg)
{
    // 从下行缓冲区读取一个字符数组消息
    char chars_buf[128];
    int len = app_buffer_read(device->down_buffer, chars_buf, sizeof(chars_buf));
    if (len == -1)
    {
        log_error("从下行缓冲区读取数据失败");
        return -1;
    }
    // 将字符数组消息转换为蓝牙格式数据
    if (len > 0 && device->pre_write)
    {
        len = device->pre_write(chars_buf, len);
        if (len == -1)
        {
            log_error("设备数据写前处理失败");
            return -1;
        }

        // 只有有数据
        if (len > 0)
        {
            // 如果距离上次写入时间间隔小于200ms，则等待不够的时间
            long long distance_time = app_common_getCurrentTime() - device->last_write_time;
            if (distance_time < 200)
            {
                usleep((200 - distance_time) * 1000);
            }

            // 写入设备文件中
            ssize_t write_len = write(device->fd, chars_buf, len);
            if (write_len != len)
            {
                log_error("写入设备文件失败");
                return -1;
            }
            log_debug("写入设备文件成功: %.*s", len, chars_buf);
            // 记录写入时间
            device->last_write_time = app_common_getCurrentTime();

            return 0;
        }
    }

    return -1;
}

/**
 * 接收远程消息的回调函数
 */
static int receive_msg_callback(char *json)
{
    log_debug("接收到远程消息：%s", json);

    // 将json消息转换为字符数组
    char chars_buf[128];
    int len = app_message_jsonToChars(json, chars_buf, sizeof(chars_buf));
    if (len == -1)
    {
        log_error("将json消息转换为字符数组失败");
        return -1;
    }
    // 将字符数组写入下行缓冲区
    int result = app_buffer_write(device->down_buffer, chars_buf, len);
    if (result == -1)
    {
        log_error("将字符数组写入下行缓冲区失败");
        return -1;
    }
    // 将保存消息数据到设备文件的操作交给线程池执行
    app_pool_registerTask(write_task_func, NULL);

    return 0;
}

/**
 * 启动设备
 * 1. 创建启动读数据
 */
int app_device_start()
{
    if (device->is_running == 1)
    {
        log_debug("设备读线程已经启动运行中");
        return 0;
    }

    // 创建启动读数据线程
    device->is_running = 1;
    pthread_create(&device->read_thread, NULL, read_thread_func, NULL);

    // 注册接收远程消息的回调函数
    app_mqtt_registerRecvCallback(receive_msg_callback);

    log_debug("设备启动完成");

    return 0;
}

/**
 * 销毁设备
 */
void app_device_destroy()
{
    // 释放缓冲区
    app_buffer_free(device->down_buffer);
    app_buffer_free(device->up_buffer);
    // 取消读线程
    pthread_cancel(device->read_thread);
    // 关闭设备文件
    close(device->fd);
    // 释放设备
    free(device);
}
